#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#include "calc.h"

int main (int argc, char** argv)
{
	if (argc != 2)
	{
		printf("Must be just one argument: name of file, that contains expression to calculate\n");
		exit(0);
	}

	dump_file = fopen("dump.txt", "w");
	
	FILE* read_file = fopen(argv[1], "r");
	expression_buffer = (char*) calloc (MAX_SIZE_OF_BUFFER, sizeof(*expression_buffer));
	assert(expression_buffer);

	fscanf(read_file, "%s", expression_buffer);
	fclose (read_file);
	read_file = NULL;
	expression_buffer_cur_pos = expression_buffer;

	long result = GetG0();
	PrintResult(result);

	free(expression_buffer);
	expression_buffer = NULL;

	fclose(dump_file);
	dump_file = NULL;
	return 0;
}

long GetG0()
{
	long result = GetE();
	if(*expression_buffer_cur_pos != '\0' && Calc_errno == GOOD_CALC) //second condition means that no other errors are detected
	{
		Calc_errno = WRONG_END_OF_BUFFER;
	}
	fprintf(dump_file, "Result of G0 is %10li|\n", result);
	return result;
}

long GetE()
{
	long result = GetT();
	while (*expression_buffer_cur_pos == '+')
	{
		expression_buffer_cur_pos++;
		result += GetT();
	}
	fprintf(dump_file, "Result of E  is %10li|\n", result); 
	return result;
}

long GetT()
{
	long result = GetP();
	while (*expression_buffer_cur_pos == '*')
	{
		expression_buffer_cur_pos++;
		result *= GetP();
	}
	fprintf(dump_file, "Result of T  is %10li|\n", result); 
	return result;
}

long GetP()
{
	long result = 0;
	if (*expression_buffer_cur_pos == '(')
	{
		expression_buffer_cur_pos++;
		result += GetE();
		if(*expression_buffer_cur_pos != ')')
		{
			Calc_errno = WRONG_CLOSE_BRACKET;
		}
		else
		{
			expression_buffer_cur_pos++;
		}
		fprintf(dump_file, "Result of P  is %10li|\n", result);
		return result;
	}
	else
	{
		return GetN();
	}
	return 0;
}

long GetN()
{
	long result = 0;
	while ('0' <= *expression_buffer_cur_pos && *expression_buffer_cur_pos <= '9')
	{
		result = result*10 + *expression_buffer_cur_pos - '0';
		expression_buffer_cur_pos++;
	}
	return result;
}

int PrintResult(long result)
{
	if (Calc_errno == GOOD_CALC)
	{
		printf("The result of calculations is %li|\n", result);
	}
	else
	{
		printf("Error: %s\n", CalcStrerror());
		int num_of_spaces = expression_buffer_cur_pos - expression_buffer + 2; //One because of cursor is BEFORE wrong symbol
                                                                                       //One more because of indexing
		printf("%s\n", expression_buffer);
		printf("%*s" , num_of_spaces, "^\n");
	}
	return 0;
}

char* CalcStrerror()
{
	switch (Calc_errno)
	{
		case           GOOD_CALC: return "Everything is good";         break;
		case WRONG_END_OF_BUFFER: return "End of buffer is not \\0";   break;
		case WRONG_CLOSE_BRACKET: return "Invalid close bracket here"; break;
		default:                  return "Some unexpected situatuion"; break;
	}
}
